import java.util.Queue;
import java.util.Random;
import java.util.TimerTask;
import java.util.List;

public class Scheduler 
{
	private static final long TIME = 100; //ms
	private static final TimerTask task = null;
	
	private long start_time;
	private long current_time;
	/**
	 * list of process control blocks.
	 */
	private PCBList my_pcb_list; 
	
	/**
	 * the current process.
	 */
	private Process my_process;
	
	/**
	 * my_pcb
	 */
	private Pcb my_pcb;
	
	/**
	 * 0= round robin, 1= lottery, and 2 = priority
	 */
	private static int my_policy; 
	
	/**
	 * remembers the id/index of the list.
	 */
	private static int last_position;
	
	private Pcb next_pcb;
	
	/**
	 * just for the round-Robin
	 */
	private boolean timeOver;
	
	public Scheduler(PCBList the_list, int the_policy)
	{
		my_pcb_list = the_list;
		my_policy = the_policy;
		usePolicy();
		my_pcb = null;
		start_time = System.currentTimeMillis();
	}

	int usePolicy() 
	{
			if(getPolicy() == 1)
			{	
				return lottery();
			}
			else if(getPolicy() == 2)
			{
				return priority();
			}
			else
			{
				return roundRobin(); //0 

			}
	}
	
	
	private int lottery() 
	{
		int list_size = my_pcb_list.size();

		Random r = new Random();
		int index = r.nextInt(list_size - 1);
		Pcb curr_pcb = my_pcb_list.get(index);
		
		while(curr_pcb.my_state != 1) // if dont have this? infinite loop...
		{
			index = r.nextInt(list_size - 1);
			curr_pcb = my_pcb_list.get(index);
		}
		
		next_pcb = my_pcb_list.get(index);
		
		CPU.setTimerInterrupt();
		return next_pcb.my_pid;
	}

	private int roundRobin()
	{
		current_time = System.currentTimeMillis();
		if(current_time - start_time >= TIME) return -1; // nothing to do
		
		// else...		
		for(int i = last_position; i < my_pcb_list.size(); i++)
		{
			my_pcb = my_pcb_list.get(i);
			
			// if reach this, is because the time of the process is over
			if(my_pcb.my_state == 1) // if is in runnable/ready state
			{
				last_position = ++i;
				
				CPU.setTimerInterrupt();
				timeOver = true;
				next_pcb = my_pcb;
			}
			
			if(i >= my_pcb_list.size() - 1) // >= because the ++i can do something not good xD
			{
				i = 0;
			}
			
			// Scrolled through the entire list, the cpu need to operate.
			// The next while of the cpu will resume this operation
			if((i+1)%my_pcb_list.size() == last_position)
			{
				return -1; // nothing to do
			}
		}
		
		return -1;
	}
	
	private int priority() 
	{
		my_pcb_list.sort();
		
		next_pcb = my_pcb_list.get(0);
		CPU.setTimerInterrupt();
		
		return next_pcb.my_pid;
	}
		
	public Pcb getNextPCB() // or the process was completed, or one interruption occurred
	{
		if(timeOver && (my_policy == 0))
		{
			resetInterrupts();
			return next_pcb;
		}
		else if(my_policy == 1)
		{
			return next_pcb;
		}
		else if(my_policy == 2)
		{
			return next_pcb;
		}
		else
		{
			for(int i = 0; i < my_pcb_list.size(); i++)
			{
				my_pcb = my_pcb_list.get(i);
				
				if(my_pcb.my_state == 1) // if is in runnable/ready state
				{
					next_pcb = my_pcb;
					
					return next_pcb;
				}
				
				if(i == my_pcb_list.size() - 1)
				{
					break;
				}
			}
		}
		return my_pcb; // ?
	}
	
	protected int getPolicy()
	{
		return my_policy;
	}
	
	protected void resetInterrupts()
	{
		timeOver = false;
		CPU.resetTimerInterrupt();
	}
	
	public void resetTimer()
	{
		start_time = System.currentTimeMillis();
	}
}
